﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using PFP.Imaging;

namespace GXImageTools
{
    public class ImageTools
    {
        private static string OriginalCurrentDirectory = "";

        public static int ErrCode = 0;
        public static string ErrDescription = "";
        

        public static void Crop(string OriginalPath, string NewPath, int x, int y, int width, int height)
        {
            ImageTools.SetContext();
            try
            {
                Bitmap img = new Bitmap(OriginalPath);
                Rectangle cropArea = new Rectangle(x, y, width, height);
                Bitmap bmpImage = new Bitmap(img);
                Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
                img.Dispose();
                bmpImage.Dispose();
                bmpCrop.Save(NewPath);
            }
            catch (Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;

            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }

        public static void Resize(string OriginalPath, string NewPath,int destWidth, int destHeight)
        {
            ImageTools.SetContext();
            try 
            {
	            Bitmap imgToResize = new Bitmap(OriginalPath);
	            Bitmap b = new Bitmap(destWidth, destHeight);
	            Graphics g = Graphics.FromImage((Image)b);
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
	            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
	            g.Dispose();
	            imgToResize.Dispose();	
	            b.Save(NewPath);
	            b.Dispose();
 	        } 
            catch(Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }

        public static void ResizeMaintainingAspectRatio(string OriginalPath, string NewPath, int Width, int Height)
        {
            ImageTools.SetContext();
            try
            {
                Bitmap imgToResize = new Bitmap(OriginalPath);

                int sourceWidth = imgToResize.Width;
                int sourceHeight = imgToResize.Height;
                int destX = 0;
                int destY = 0;

                float nPercent = 0;
                float nPercentW = 0;
                float nPercentH = 0;

                nPercentW = ((float)Width / (float)sourceWidth);
                nPercentH = ((float)Height / (float)sourceHeight);
                if (nPercentH < nPercentW)
                {
                    nPercent = nPercentH;
                    destX = Convert.ToInt16((Width - (sourceWidth * nPercent)) / 2);
                }
                else
                {
                    nPercent = nPercentW;
                    destY = Convert.ToInt16((Height - (sourceHeight * nPercent)) / 2);
                }

                int destWidth = (int)(sourceWidth * nPercent);
                int destHeight = (int)(sourceHeight * nPercent);



                Bitmap b = new Bitmap(destWidth, destHeight);
                Graphics g = Graphics.FromImage((Image)b);
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
                g.Dispose();
                imgToResize.Dispose();
                b.Save(NewPath);
                b.Dispose();
            }
            catch (Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }

       

        public static void Rotate(string OriginalPath, string NewPath)
        {
            ImageTools.SetContext();
            try 
            {
	            //create an object that we can use to examine an image file
	             Image img = Image.FromFile(OriginalPath);
     
                //rotate the picture by 90 degrees
	            img.RotateFlip(RotateFlipType.Rotate90FlipNone);
                
	            img.Save(NewPath);
	            img.Dispose();
    	
 	        } 
            catch(Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
       }

        public static void RotateByAngle(string OriginalPath, string NewPath, float angle)
        {
            ImageTools.SetContext();
            try
            {
                //create an object that we can use to examine an image file
                Image img = Image.FromFile(OriginalPath);

                Bitmap b = new Bitmap(img);
                Bitmap newBitmap = new Bitmap(b.Width, b.Height);
                Graphics objGraphics = Graphics.FromImage(newBitmap);

                
                objGraphics.TranslateTransform((float)img.Width / 2, (float)img.Height / 2);
                objGraphics.RotateTransform(angle);
                objGraphics.TranslateTransform(-(float)img.Width / 2, -(float)img.Height / 2);
                objGraphics.DrawImage(b, new Point(0, 0));
                //objGraphics.Dispose();
                img = newBitmap;
                img.Save(NewPath);
                img.Dispose();

            }
            catch (Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }

        public static void GenerateFromText(string OutputPath,string Text,string FontName,int Size)
        {
        try
        {
            ImageTools.SetContext();
 		    Bitmap objBmpImage = new Bitmap(1, 1);
      
 		      int intWidth = 0;
 		      int intHeight = 0;

			  // Create the Font object for the image text drawing.
              Font objFont = new Font(FontName, Size, FontStyle.Bold, GraphicsUnit.Pixel);
                     // Create a graphics object to measure the text's width and height.
              Graphics objGraphics = Graphics.FromImage(objBmpImage);
             
               // This is where the bitmap size is determined.
              intWidth = (int)objGraphics.MeasureString(Text, objFont).Width;
              intHeight = (int)objGraphics.MeasureString(Text, objFont).Height;

              // Create the bmpImage again with the correct size for the text and font.
              objBmpImage = new Bitmap(objBmpImage, new Size(intWidth, intHeight));

              // Add the colors to the new bitmap.
              objGraphics = Graphics.FromImage(objBmpImage);

               // Set Background color
              objGraphics.Clear(Color.White);
              objGraphics.SmoothingMode =  SmoothingMode.AntiAlias;
              objGraphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
              objGraphics.DrawString(Text, objFont, new SolidBrush(Color.FromArgb(0, 0, 0)), 0, 0);
              objGraphics.Flush();
              objBmpImage.Save(OutputPath, System.Drawing.Imaging.ImageFormat.Jpeg);
 	  } 
        catch(Exception ex) 
        {
            ErrDescription = ex.Message;
            ErrCode = 1;
        }
        finally
        {
            ImageTools.UnsetContext();
        }

        }

        public static void ChangeFormat(string OriginalPath,string NewPath,int Quality,string ImageFormat)
        {
            ImageTools.SetContext();
            try 
            {
                Bitmap img = new Bitmap(OriginalPath);
   		        // Encoder parameter for image quality
                EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)Quality);
                ImageCodecInfo codec = GetEncoderInfo(ImageFormat);

                if (codec == null)
                {
                    ErrDescription = ImageFormat + " format error";
                    ErrCode = 1;
                }
                else
                {
                    EncoderParameters encoderParams = new EncoderParameters(1);
                    encoderParams.Param[0] = qualityParam;

                    img.Save(NewPath, codec, encoderParams);
                    img.Dispose();
                }
 	        }
            catch(Exception ex) 
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }

        public static void GenerateThumbnail(string OriginalPath,string NewPath,int destHeight,int destWidth,int Color)
        {
          ImageTools.SetContext();
   	      try 
          {
	        System.Drawing.Bitmap imgToResize = new System.Drawing.Bitmap(OriginalPath);
	        System.Drawing.Image imgPhoto = FixedSize((System.Drawing.Image)imgToResize, destWidth, destHeight,(Int32)Color);
	        imgToResize.Dispose();
	        imgPhoto.Save(NewPath, System.Drawing.Imaging.ImageFormat.Jpeg);
	        imgPhoto.Dispose();
 	      } 
          catch(Exception ex) 
          {
              ErrDescription = ex.Message;
              ErrCode = 1;
          }
          finally
          {
              ImageTools.UnsetContext();
          }
        }

        public static void GetSize(string Path, int Width, int Height)
        {
            ImageTools.SetContext();
            try
            {
                Bitmap img = new Bitmap(Path);

                Width = img.Width;
                Height = img.Height;
                img.Dispose();
            }
            catch (Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }
        
        public static void Combine(List<string> files, string NewPath)
        {
            // from: http://www.switchonthecode.com/tutorials/combining-images-with-
            ImageTools.SetContext();
            //read all images into memory
            List<System.Drawing.Bitmap> images = new List<System.Drawing.Bitmap>();
            System.Drawing.Bitmap finalImage = null;

            try
            {
                int width = 0;
                int height = 0;

                foreach (string image in files)
                {
                    //create a Bitmap from the file and add it to the list
                    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(image);

                    //update the size of the final bitmap
                    width += bitmap.Width;
                    height = bitmap.Height > height ? bitmap.Height : height;

                    images.Add(bitmap);
                }

                //create a bitmap to hold the combined image
                finalImage = new System.Drawing.Bitmap(width, height);

                //get a graphics object from the image so we can draw on it
                using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(finalImage))
                {
                    //set background color
                    g.Clear(System.Drawing.Color.Black);

                    //go through each image and draw it on the final image
                    int offset = 0;
                    foreach (System.Drawing.Bitmap image in images)
                    {
                        g.DrawImage(image,
                          new System.Drawing.Rectangle(offset, 0, image.Width, image.Height));
                        offset += image.Width;
                    }
                }

                finalImage.Save(NewPath);
                finalImage.Dispose();
            }
            catch (Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
            }
            finally
            {
                //clean up memory
                foreach (System.Drawing.Bitmap image in images)
                {
                    image.Dispose();
                }
                ImageTools.UnsetContext();
            }
        }

        public static List<string> GetProperties(string Path)
        {
            try
            {

                Image metaImage = Image.FromFile(Path);
                List<string> res = new List<string>();
                Dictionary<PropertyTagId, KeyValuePair<PropertyTagType, Object>> returnImageProps = new Dictionary<PropertyTagId, KeyValuePair<PropertyTagType, object>>();

                foreach (PropertyItem property in metaImage.PropertyItems)
                {
                    Object propValue = new Object();
                    switch ((PropertyTagType)property.Type)
                    {
                        case PropertyTagType.ASCII:
                            ASCIIEncoding encoding = new ASCIIEncoding();
                            propValue = encoding.GetString(property.Value, 0, property.Len - 1);
                            break;
                        case PropertyTagType.Int16:
                            propValue = BitConverter.ToInt16(property.Value, 0);
                            break;
                        case PropertyTagType.SLONG:
                        case PropertyTagType.Int32:
                            propValue = BitConverter.ToInt32(property.Value, 0);
                            break;
                        case PropertyTagType.SRational:
                        case PropertyTagType.Rational:
                            UInt32 numberator = BitConverter.ToUInt32(property.Value, 0);
                            UInt32 denominator = BitConverter.ToUInt32(property.Value, 4);

                            if (denominator != 0)
                                propValue = ((double)numberator / (double)denominator).ToString();
                            else
                                propValue = "0";

                            if (propValue.ToString() == "NaN")
                                propValue = "0";
                            break;
                        case PropertyTagType.Undefined:
                            propValue = "Undefined Data";
                            break;
                    }
                    returnImageProps.Add(NumToEnum<PropertyTagId>(property.Id), new KeyValuePair<PropertyTagType, object>(NumToEnum<PropertyTagType>(property.Type), propValue));
                }

                foreach (KeyValuePair<PropertyTagId, KeyValuePair<PropertyTagType, Object>>
                    property in returnImageProps)
                {
                    res.Add(property.Key.ToString() + ": " + property.Value.ToString());
                }
                return res;
            }
            catch (Exception ex)
            {
                ErrDescription = ex.Message;
                ErrCode = 1;
                return null;
            }
            finally
            {
                ImageTools.UnsetContext();
            }
        }


        private static T NumToEnum<T>(int number)
        {
            return (T)Enum.ToObject(typeof(T), number);
        }

        private static Image FixedSize(Image imgPhoto, int Width, int Height, Int32 myColor)
        {
            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;
            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)Width / (float)sourceWidth);
            nPercentH = ((float)Height / (float)sourceHeight);
            if (nPercentH < nPercentW)
            {
                nPercent = nPercentH;
                destX = Convert.ToInt16((Width - (sourceWidth * nPercent)) / 2);
            }
            else
            {
                nPercent = nPercentW;
                destY = Convert.ToInt16((Height - (sourceHeight * nPercent)) / 2);
            }

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap bmPhoto = new Bitmap((Int32)Width, (Int32)Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

            System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(bmPhoto);
            grPhoto.Clear(System.Drawing.Color.FromArgb(myColor));
            grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            grPhoto.DrawImage(imgPhoto, new System.Drawing.Rectangle(destX, destY, destWidth, destHeight), new System.Drawing.Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), System.Drawing.GraphicsUnit.Pixel);

            grPhoto.Dispose();
            return bmPhoto;
        }

    
        private static ImageCodecInfo GetEncoderInfo(string mimeType)
        {
            // Get image codecs for all image formats
            ImageCodecInfo[/**/] codecs = ImageCodecInfo.GetImageEncoders();

            // Find the correct image codec
            for (int i = 0; i < codecs.Length; i++)
                if (codecs[i].MimeType == mimeType)
                    return codecs[i];
            return null;
        }

        private static void SetContext()
        {
            try
            {
                ErrCode = 0;
                OriginalCurrentDirectory = System.IO.Directory.GetCurrentDirectory();
                if (System.IO.Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).FullName!=null)
                System.IO.Directory.SetCurrentDirectory(System.IO.Directory.GetParent(AppDomain.CurrentDomain.BaseDirectory).FullName);
            }
            catch
            {
            }
        }

        private static void UnsetContext()
        {
            try
            {
                System.IO.Directory.SetCurrentDirectory(OriginalCurrentDirectory);
            }
            catch
            {
            }
        }

    }
}
